package com.ckm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ckm.dto.StudentCourseInfoDto;
import com.ckm.dto.StudentScoreDto;
import com.ckm.entity.*;
import com.ckm.exception.BusinessException;
import com.ckm.mapper.*;
import com.ckm.service.StudentCourseService;
import com.ckm.util.ExcelUtils;
import com.ckm.util.FindObjectUtil;
import com.ckm.util.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class StudentCourseServiceImpl implements StudentCourseService {

    static String channel = "queue";

    @Autowired
    private StudentCourseMapper studentCourseMapper;
    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private ClassesMapper classesMapper;
    @Autowired
    private MajorMapper majorMapper;
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private TeacherCourseMapper teacherCourseMapper;

    @Override
    public void addStudentCourse(List<StudentCourse> studentCourseList) {
        if (studentCourseList == null || studentCourseList.isEmpty()) {
            throw new BusinessException(250,"添加数据集为空");
        }
        for (StudentCourse studentCourse : studentCourseList) {
            if (!findStudentCourse(studentCourse).isEmpty()) {
                throw new BusinessException(250,"数据重复:"+studentCourse);
            }
            studentCourseMapper.insert(studentCourse);
        }
        log.info("添加数据：{}", studentCourseList);
    }

    @Override
    public void deleteStudentCourse(Integer id) {
        if (id==null){
            throw new BusinessException(250,"删除参数为空");
        }
        if (studentCourseMapper.selectById(id)==null){
            throw new BusinessException(250,"无此选课");
        }
        studentCourseMapper.deleteById(id);
    }

    @Override
    public void updateStudentCourse(StudentCourse studentCourse) {
        if (studentCourse.getId()==null){
            throw new BusinessException(250,"更新信息缺少id");
        }
        StudentCourse select = studentCourseMapper.selectById(studentCourse.getId());
        if (select==null){
            throw new BusinessException(250,"无此选课");
        }
        if (select.equals(studentCourse)){
            throw new BusinessException(250,"信息无更改");
        }
        studentCourseMapper.updateById(studentCourse);
    }

    @Override
    public PageInfo<StudentCourse> getStudentCoursePage(StudentCourse studentCourse, int pageNum, int pageSize) {
        QueryWrapper<StudentCourse> wrapper = new QueryWrapper<>();
        FindObjectUtil.fullQueryWrapper(studentCourse,wrapper);
        PageHelper.startPage(pageNum, pageSize);
        List<StudentCourse> list = studentCourseMapper.selectList(wrapper);
        return new PageInfo<>(list);
    }

    @Override
    public List<StudentCourse> findStudentCourse(StudentCourse studentCourse) {
        QueryWrapper<StudentCourse> wrapper = new QueryWrapper<>();
        FindObjectUtil.fullQueryWrapper(studentCourse,wrapper);
        return studentCourseMapper.selectList(wrapper);
    }

    @Override
    public Map<String, Object> statistics(String courseName) {
        List<Course> courseList = courseMapper.selectList(new QueryWrapper<Course>().eq("course_name", courseName));
        if (courseList == null || courseList.isEmpty()) {
            throw new BusinessException(250,"查找不到此课程："+courseName);
        }
        List<StudentCourse> studentCourseList =
                studentCourseMapper.selectList(new QueryWrapper<StudentCourse>().eq("course_id", courseList.getFirst().getId()));
        if (studentCourseList == null || studentCourseList.isEmpty()) {
            throw new BusinessException(250,"课程："+courseName+"，暂无学生");
        }
        //获取未打分学生list
        List<StudentCourse> scoreNull =
                studentCourseList.stream()
                        .filter(f -> f.getScore() == null).toList();
        //将已经打分的学生按60.0分为两组
        Map<Boolean, List<StudentCourse>> map =
                studentCourseList.stream()
                        .filter(f->f.getScore() != null)
                        .sorted(Comparator
                                .comparingDouble(StudentCourse::getScore)
                                .reversed())
                        .collect(Collectors
                                .partitioningBy(x -> x.getScore() < 60.0));
        //将已经打分的学生按分数高低进行排序
        List<StudentCourse> list = studentCourseList.stream()
                .filter(f->f.getScore() != null)
                .sorted(Comparator
                        .comparingDouble(StudentCourse::getScore)
                        .reversed()).toList();
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("courseName", courseName);
        ArrayList<Map<String,Object>> courseMap = new ArrayList<>();
        //对已经打分的学生进行统计
        map.forEach((k,v)->{
            Map<String, Object> scoreMap = new LinkedHashMap<>();
            if (k){
                scoreMap.put("pass","不及格");
            }else {
                scoreMap.put("pass","及格");
            }
            List<Map<String, Object>> studentList = new ArrayList<>();
            v.forEach(v1->{
                Map<String, Object> studentMap = new LinkedHashMap<>();
                studentMap.put("studentName",studentMapper.selectById(v1.getStuId()).getName());
                studentMap.put("score",v1.getScore());
                studentMap.put("rank",list.indexOf(v1)+1);
                studentList.add(studentMap);
            });
            scoreMap.put("studentList",studentList);
            courseMap.add(scoreMap);
        });
        List<Map<String, Object>> studentList = new ArrayList<>();
        //对未打分的学生进行统计
        for (StudentCourse studentCourse : scoreNull) {
            Map<String, Object> studentMap = new LinkedHashMap<>();
            studentMap.put("studentName",studentMapper.selectById(studentCourse.getStuId()).getName());
            studentList.add(studentMap);
        }
        Map<String, Object> scoreMap = new LinkedHashMap<>();
        scoreMap.put("pass","未打分");
        scoreMap.put("studentList",studentList);
        courseMap.add(scoreMap);
        result.put("scores",courseMap);
        //计算总体学生通过考核率
        //及格人数
        long count = studentCourseList.stream()
                .filter(f -> f.getScore() != null)
                .filter(f -> f.getScore() >= 60.0)
                .count();
        result.put("rate", ((double)count/(double)studentCourseList.size()));
        return result;
    }

    @Override
    public void chooseStudentCourse(StudentCourse studentCourse) {
        Course course = courseMapper.selectById(teacherCourseMapper.selectById(studentCourse.getTchCourseId()));
        Student student = studentMapper.selectById(studentCourse.getStuId());
        if (course==null || student==null){
            throw new BusinessException(250,"参数有误");
        }
        List<StudentCourse> studentCourseList = findStudentCourse(studentCourse);
        if (!studentCourseList.isEmpty()) {
            throw new BusinessException(250,"已经选课");
        }
        String key = "choose"+course.getCourseName();
        if (Boolean.FALSE.equals(redisTemplate.hasKey(key))){
            throw new BusinessException(250,"该课程尚未开放选课");
        }
        //判断人数
        Integer size = (Integer) redisTemplate.opsForValue().get(key);
        assert size != null;
        if (size==0){
            throw new BusinessException(250,"该课程人数已满");
        }
        //-1
        redisTemplate.opsForValue().decrement(key);
        //传输信息给消息队列
        redisTemplate.convertAndSend(channel,studentCourse);
    }

    @Override
    public PageInfo<?> allStudentCourseByMajor(int pageNum,int pageSize,String majorName) {
        Major major = majorMapper.selectOne(new QueryWrapper<Major>().eq("major_name", majorName));
        if (major==null){
            throw new BusinessException(250,"不存在该专业");
        }
        List<Classes> classesList = classesMapper.selectList(new QueryWrapper<Classes>().eq("major_id", major.getId()));
        if (classesList.isEmpty()){
            throw new BusinessException(250,"该专业下不存在班级");
        }
        List<Student> studentList = studentMapper.selectList(
                new QueryWrapper<Student>()
                        .in("class_id", classesList.stream().map(Classes::getId).collect(Collectors.toList())));
        if (studentList.isEmpty()){
            throw new BusinessException(250,"该专业下不存在学生");
        }
        ArrayList<StudentScoreDto> studentScoreDtoList = new ArrayList<>();
        for (Student student : studentList) {
            StudentScoreDto studentScoreDto = new StudentScoreDto();
            studentScoreDto.setName(student.getName());
            List<StudentCourse> studentCourseList = studentCourseMapper.selectList(new QueryWrapper<StudentCourse>().eq("stu_id", student.getId()));
            ArrayList<StudentCourseInfoDto> list = new ArrayList<>(studentCourseList.size());
            for (StudentCourse course : studentCourseList) {
                list.add(getStudentCourseInfoDto(course));
            }
            studentScoreDto.setCourseInfoDtoList(list);

            studentScoreDtoList.add(studentScoreDto);
        }
        for (StudentScoreDto studentScoreDto : studentScoreDtoList) {
            int sum = 0;
            float average = 0,creditTotal = 0;
            for (StudentCourseInfoDto studentCourseInfoDto : studentScoreDto.getCourseInfoDtoList()) {
                if (studentCourseInfoDto.getScore()!=null){
                    sum += studentCourseInfoDto.getScore();
                    creditTotal += studentCourseInfoDto.getCredit();
                    if (((float) studentCourseInfoDto.getScore() /10 - 5)>=1){
                        average += ((float) studentCourseInfoDto.getScore() /10 - 5) * studentCourseInfoDto.getCredit();
                    }
                }
            }
            if (creditTotal != 0){
                studentScoreDto.setAverage(average/creditTotal);
            }
            studentScoreDto.setTotal(sum);
        }
        List<StudentScoreDto> list = studentScoreDtoList
                .stream()
                .sorted(Comparator.comparing(StudentScoreDto::getTotal).reversed())
                .skip((long) (pageNum - 1) * pageSize)
                .limit(pageSize)
                .toList();
        return PageUtil.getPage(pageNum,pageSize,list);
    }

    @Override
    public List<StudentCourseInfoDto> studentScore(StudentCourseInfoDto studentCourseInfoDto,int pageNum,int pageSize) {
        List<StudentCourse> courseList = null;
        //根据学生姓名查询
        if (studentCourseInfoDto.getStudentName()!=null && !studentCourseInfoDto.getStudentName().isEmpty()){
            Student student = studentMapper.selectOne(new QueryWrapper<Student>().eq("name", studentCourseInfoDto.getStudentName()));
            if (student==null){
                throw new BusinessException(250,"无此学生");
            }
            courseList = studentCourseMapper.selectList(new QueryWrapper<StudentCourse>().eq("stu_id", student.getId()));
            if (courseList.isEmpty()){
                return null;
            }
        }
        List<StudentCourse> studentList = null;
        //根据课程名称查询
        if (studentCourseInfoDto.getCourseName()!=null && !studentCourseInfoDto.getCourseName().isEmpty()){
            Course course = courseMapper.selectOne(new QueryWrapper<Course>().eq("course_name", studentCourseInfoDto.getCourseName()));
            if (course==null){
                throw new BusinessException(250,"无此课程");
            }
            List<TeacherCourse> teacherCourseList = teacherCourseMapper.selectList(new QueryWrapper<TeacherCourse>().eq("course_id", course.getId()));
            if (teacherCourseList.isEmpty()){
                throw new BusinessException(250,"无此课程任课老师");
            }
            studentList = studentCourseMapper.selectList(
                    new QueryWrapper<StudentCourse>()
                            .in("tch_course_id", teacherCourseList.stream().map(TeacherCourse::getId).toList()));
            if (studentList.isEmpty()){
                return null;
            }
        }
        ArrayList<StudentCourseInfoDto> list = new ArrayList<>();
        //整合需要返回的结果集
        if (courseList==null && studentList==null){
            courseList = findStudentCourse(null);
        }else if (courseList!=null && studentList!=null){
            courseList.retainAll(studentList);
        }else {
            courseList = courseList==null?studentList:courseList;
        }
        //遍历整合后的结果，并转换
        for (StudentCourse studentCourse : courseList) {
            list.add(getStudentCourseInfoDto(studentCourse));
        }
        return list;
    }

    /**
     * 将StudentCourse转为StudentCourseInfoDto
     * @param studentCourse 参数
     * @return 转化完成后的值
     */
    private StudentCourseInfoDto getStudentCourseInfoDto(StudentCourse studentCourse){
        StudentCourseInfoDto infoDto = new StudentCourseInfoDto();
        Student student = studentMapper.selectOne(new QueryWrapper<Student>().eq("id", studentCourse.getStuId()));
        Course course =
                courseMapper.selectById(
                        teacherCourseMapper.selectById(studentCourse.getTchCourseId())
                                .getCourseId());
        infoDto.setStudentName(student.getName());
        infoDto.setStuId(student.getId());
        infoDto.setCourseName(course.getCourseName());
        infoDto.setScore(studentCourse.getScore());
        infoDto.setCredit(course.getCredit());
        infoDto.setTchCourseId(studentCourse.getTchCourseId());
        return infoDto;
    }

    @Override
    public void outputStudentScore(String courseName, Integer teacherId, HttpServletResponse response) {
        Course course = courseMapper.selectOne(new QueryWrapper<Course>().eq("course_name", courseName));
        if (course==null){
            throw new BusinessException(250,"无此课程");
        }
        TeacherCourse teacherCourse = teacherCourseMapper.selectOne(new QueryWrapper<TeacherCourse>().eq("tch_id", teacherId).eq("course_id", course.getId()));
        if (teacherCourse==null){
            throw new BusinessException(250,"该老师无权限");
        }
        List<StudentCourse> studentCourseList = studentCourseMapper.selectList(new QueryWrapper<StudentCourse>().eq("course_id", course.getId()));
        if (studentCourseList == null || studentCourseList.isEmpty()) {
            throw new BusinessException(250,"课程："+courseName+"，暂无学生");
        }
        List<StudentCourse> list1 = new ArrayList<>(studentCourseList.stream()
                .filter(f -> f.getScore() != null)
                .sorted(Comparator.comparing(StudentCourse::getScore).reversed())
                .toList());
        List<StudentCourse> list2 = studentCourseList.stream().filter(f -> f.getScore() == null).toList();
        list1.addAll(list2);
        String[] head = {"姓名","成绩"};
        List<List<Object>> dataList = new ArrayList<>();
        for (StudentCourse studentCourse : list1) {
            ArrayList<Object> objects = new ArrayList<>();
            objects.add(studentMapper.selectById(studentCourse.getStuId()).getName());
            objects.add(studentCourse.getScore());
            dataList.add(objects);
        }
        ExcelUtils.writeExcel(head,dataList,courseName+"成绩表.xlsx",response);
    }

    @Override
    public List<StudentCourseInfoDto> rankStudentScore(StudentCourseInfoDto studentCourseInfoDto, int pageNum, int pageSize) {
        List<StudentCourseInfoDto> list = studentScore(studentCourseInfoDto, pageNum, pageSize);
        for (StudentCourseInfoDto infoDto : list) {
            List<StudentCourse> studentCourseList = studentCourseMapper.selectList(new QueryWrapper<StudentCourse>().eq("tch_course_id", infoDto.getTchCourseId()));
            List<StudentCourse> result = studentCourseList.stream().filter(f -> f.getScore() != null).sorted(Comparator.comparing(StudentCourse::getScore).reversed()).toList();
            for (int i = 0; i < result.size(); i++) {
                if (Objects.equals(result.get(i).getStuId(), infoDto.getStuId())
                        && Objects.equals(result.get(i).getTchCourseId(), infoDto.getTchCourseId())){
                    infoDto.setRank(i+1);
                    break;
                }
            }
        }
        return list;
    }
}
